home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / umich / sound / players / waveplay.zoo / wave.c < prev    next >
C/C++ Source or Header  |  1993-07-20  |  14KB  |  445 lines

  1. /**************************************************************
  2. *       this program will play a "wave" file on an ATARI TT   *
  3. *                                                             *
  4. *  Algorithm:                                                 *
  5. *      open file                                              *
  6. *      Read the header of the file.                           *
  7. *      if the header is not valid report that and exit        *
  8. *      If file is an "RIFF" file convert to motorola integers *
  9. *      allocate memory (ST-RAM) for PCM data                  *
  10. *      Read the PCM data                                      *
  11. *      close the file                                         *
  12. *      If sample is 8 bit then convert data to ATARI format   *
  13. *      play the Sample                                        *
  14. *      wait until sample is completed                         *
  15. *      free memory                                            *
  16. *      exit                                                   *
  17. *                                                             *
  18. *                                                             *
  19. *  Change History:                                            *
  20. *                                                             *
  21. *  12/10/92    Added ability to accept filenames from stdin      *
  22. *  12/13/92 Corrected Error msgs relating to memory allocs    *
  23. *                                                             *
  24. **************************************************************/
  25. /*
  26.     The correct method of reading a WAV file is to
  27.     read in the RIFF/RIFX chunk id and size along with
  28.     the WAVE identifier.
  29.     while not the end of the file (WAV files can contain multiple samples)
  30.     Begin
  31.       Read in the next chunk identifier
  32.       while the identifier is not "fmt\0"
  33.       Begin       (typically this section willnever be used)
  34.         report type of chunk encountered.
  35.         skip this chunk.
  36.         read in the next chunk identifier
  37.         End (ckID not "fmt\0")
  38.       read in the "fmt\0" chunk data
  39.       Read in the next chunk identifier
  40.       while the identifier is not "data"
  41.       Begin
  42.         report type of chunk encountered.
  43.         skip this chunk.
  44.         read in the next chunk identifier
  45.         End (ckID not "data")
  46.       read in the data
  47.       one second of sample at a time
  48.       Begin
  49.         re-sample the data (if needed otherwise copy)
  50.         play the 1 second
  51.         End (One second at a time)
  52.       End (Not end of file)
  53. */
  54.  
  55. /*
  56.   Things to be added:
  57.     1) take filenames from STDIN
  58.     2) optionally supress messages to stdout/stderr
  59. */
  60.  
  61. #include <stdio.h>
  62. #include <stdlib.h>
  63. #include <string.h>
  64. #include <tos.h>
  65. #include "stereo.h"
  66. #include "riff.h"
  67.  
  68. #define FALSE 0
  69. #define TRUE  1
  70. #define MAX_FNAME_LENGTH 132
  71. #define FROM_START_OF_FILE 0
  72. #define FROM_END_OF_FILE   2
  73. void FatalError (char * id) ;
  74. void MSC_cnvrt_int(INTEGER * i) ;
  75. void MSC_cnvrt_long(LONG * i) ;
  76. void Convert_MSC_ATARI_8_Bit(unsigned char * c, unsigned long i) ;
  77. long Play_PCM_Sample() ;
  78. void process_file(char * fname) ;
  79. int  locate_chunk(char * id_fmt, CHK_DEF * Chk, FILE * fp) ;
  80.  
  81. char cmd[132] ;
  82. char *id_riff = "RIFF";
  83. char *id_rifx = "RIFX";
  84. char *id_wave = "WAVE";
  85. char *id_fmt  = "fmt ";
  86. char *id_data = "data" ;
  87. WAVE_DEFINITION  *wave ;
  88. PCM_Samples       origSample ;
  89. int               motorola_fmt ;
  90.  
  91. main(argc, argv)
  92. int argc ;
  93. char *argv[] ;
  94. {
  95. unsigned long   i ;
  96. char            fname[MAX_FNAME_LENGTH] ;
  97.  
  98.   strcpy(cmd, argv[0]) ;
  99.   fname[0] = '\0' ;
  100.   if (argc > 1)
  101.     for (i = 1; i < argc; i++) 
  102.     {
  103.       if (argv[i][0] != '-')
  104.       {
  105.         printf("%s -", argv[i]) ;
  106.         process_file(argv[i]) ;
  107.       }
  108.     }
  109.   else
  110.   while (fgets(fname, MAX_FNAME_LENGTH, stdin) != NULL)
  111.     process_file(fname) ;
  112.   return 0 ;
  113. }
  114.  
  115. void process_file(char * fname)
  116. {
  117. long            num_read ;
  118. unsigned long   nSamples ;
  119. double          Sample_length ;
  120. long            BytesPerSample ;
  121. long            file_size ;
  122. long            file_pos ;
  123. PCM_Samples     Dest ;
  124. WAVE_FILE       riffChk ;
  125. CHK_DEF         fmtChk ;
  126. FILE          * fp ;
  127.  
  128.   motorola_fmt = FALSE ;
  129.   if (strcmp(fname,"-")==0) 
  130.   { 
  131.     fp = stdin;  
  132.     fname = "<stdin>"; 
  133.   }
  134.   else 
  135.     fp = fopen(fname,"rb");
  136.  
  137.   fseek(fp,0l, FROM_END_OF_FILE) ;
  138.   file_size = ftell(fp) ;
  139.   fseek(fp,0l, FROM_START_OF_FILE) ;
  140.   if (fp == NULL)
  141.     FatalError("could not open file.") ;    
  142.  
  143.   wave = (WAVE_DEFINITION *) malloc(sizeof(WAVE_DEFINITION)) ;
  144.   if (!wave)
  145.     FatalError("not enough memory to read '*.WAV' file header");
  146.  
  147.   num_read = fread(&riffChk, 1, sizeof(WAVE_FILE), fp) ;
  148.   if (num_read != sizeof(WAVE_FILE))
  149.     FatalError("WAV 'riff' header read failed");
  150.  
  151.   if (strncmp(riffChk.riffStr, id_riff, 4))
  152.   {
  153.     if (strncmp(riffChk.riffStr, id_rifx, 4))
  154.       FatalError("not an RIFF/RIFX file");
  155.     else
  156.       motorola_fmt = TRUE ;
  157.   }
  158.   if (strncmp(riffChk.waveStr, id_wave, 4))
  159.     FatalError("not a WAVE file");
  160.  
  161. /*
  162.    We now are going to have to possible loop through
  163.    many "chunks" of information to locate the format
  164.    "fmt" chunk for this WAVe file.
  165. */
  166.   if (locate_chunk(id_fmt, &fmtChk, fp) == -1)
  167.   {
  168.     FatalError("EOF encountered before 'fmt' chunk") ;
  169.   }
  170.  
  171.   num_read = fread(&(wave->hdr),1, sizeof(WAVE_HDR), fp) ;
  172.   if (num_read != sizeof(WAVE_HDR))
  173.     FatalError("WAVE header read failed");
  174.  
  175.   if (locate_chunk(id_data, &(wave->data), fp) == -1)
  176.   {
  177.     FatalError("EOF encountered before 'data' chunk") ;
  178.   }
  179. /*
  180.   because some sample wave files are incomplete the next few
  181.   lines will make adjustments to try and fix that.
  182. */
  183.   file_pos = ftell(fp) ;
  184.   if ((file_pos + wave->data.ckSize) > file_size)
  185.   {
  186.     wave->data.ckSize = file_size - file_pos ;
  187.   }
  188. /* do we need to change the integer storage format to motorola? */
  189.   if (motorola_fmt == FALSE)
  190.   {
  191.     MSC_cnvrt_long(&riffChk.ckSize) ;
  192. /*
  193.     MSC_cnvrt_long(&fmtChk.ckSize) ;
  194. */
  195.     MSC_cnvrt_int(&wave->hdr.formatTag) ;
  196.     MSC_cnvrt_int(&wave->hdr.nChannels) ;
  197.     MSC_cnvrt_long(&wave->hdr.nSamplesPerSec) ;
  198.     MSC_cnvrt_long(&wave->hdr.nAvgBytesPerSec) ;
  199.     MSC_cnvrt_int(&wave->hdr.nBlockAlign) ;
  200.     MSC_cnvrt_int(&wave->hdr.nBitsPerSample) ;
  201. /*
  202.     MSC_cnvrt_long(&wave->data.ckSize) ;
  203. */
  204.   }
  205.   if (wave->hdr.nChannels > 2)
  206.     FatalError("can not accept more than 2 channels in file") ;
  207.  
  208.  
  209. /* 
  210.     Since the STe/TT only support 8 bit PCM codes
  211.     We need to determine the correct amount of memory.
  212.     We also must take into consideration that that WAVE
  213.     file may not be sampled at the same rate the STe/TT
  214.     can play it back. So we may need to peform a little
  215.     DSP to reconstruct the sample so the Atari can play it
  216.     correctly.
  217. */
  218.  
  219. /* Determine memory requirements */
  220.   BytesPerSample = (wave->hdr.nBitsPerSample + 7) / 8 ;
  221.   if (BytesPerSample > 2)
  222.     FatalError("can not accept more than 2 bytes per sample") ;
  223.  
  224.   if ( wave->hdr.nSamplesPerSec <= SSS_RATE_50kHz )
  225.     wave->Target_SpS = SSS_RATE_50kHz ;
  226.   if ( wave->hdr.nSamplesPerSec <= SSS_RATE_25kHz )
  227.     wave->Target_SpS = SSS_RATE_25kHz ;
  228.   if ( wave->hdr.nSamplesPerSec <= SSS_RATE_12kHz )
  229.     wave->Target_SpS = SSS_RATE_12kHz ;
  230.   if ( wave->hdr.nSamplesPerSec <= SSS_RATE_6kHz )
  231.     wave->Target_SpS = SSS_RATE_6kHz ;
  232.  
  233. /*
  234.    determine the number of seconds the sample will play for 
  235. */
  236.   nSamples = (wave->data.ckSize / wave->hdr.nChannels)/ BytesPerSample ;
  237.   Sample_length = (double)nSamples / (double)wave->hdr.nSamplesPerSec ;
  238.  
  239.   printf("WAVE file contents:\n") ;
  240.   printf("  %d bit", wave->hdr.nBitsPerSample) ;
  241.   if (wave->hdr.nChannels == 2)
  242.     printf(" Stereo\n") ;
  243.   else
  244.     printf(" Mono\n") ;
  245.   printf("Sample Rate:\n   Original : %ld\n   Playback :%ld\n",
  246.          wave->hdr.nSamplesPerSec, wave->Target_SpS) ;
  247.   printf("  %lf seconds playing time\n", Sample_length) ;
  248.  
  249. /*
  250.    determine the number of bytes required to hold
  251.    sample at a rate that the Atari can play back.
  252. */
  253.   wave->required_memory = (unsigne